/**
  ******************************************************************************
  * @file    main.c
  * @author  ashuai0110
  * @version V1.0
  * @date    2024-03-04
  * @brief   使用举例-ymodem
  *
  ******************************************************************************
  * @attention
  *
  * 版权声明:内容为编者(ashuai0110)原创,使用请注明出处,当然,你也可以不这样做^_^
  * 出处链接:https://gitee.com/ashuai0110/mcu_reuse_development_module
  *
  ******************************************************************************
  */

/* 包含头文件-----------------------------------------------------------------*/
#include "stm32f10x.h"
#include "usart_dma.h"
#include "tim.h"

#include "ymodem.h"

/* 私有宏定义-----------------------------------------------------------------*/
#define YMODEM_TX_RX_TEST               (1u) /* 0:测试发送 1:测试接收 */

/* 私有类型定义---------------------------------------------------------------*/

/* 私有变量-------------------------------------------------------------------*/
static uint8_t usart1DmaTxBuf[200]; /* 串口1dma发送缓存区 */
static uint8_t usart1DmaRxBuf[200]; /* 串口1dma接收缓存区 */

static ymodem_t ymodem; /* ymodem实例 */
static uint8_t ymodemBuf[1029]; /* ymodem数据缓存区 */
static file_info_t fileInfo; /* 文件信息结构体 */

static uint8_t fileCnt = 0; /* 文件计数 */
static uint32_t sendCnt = 0; /* 已发送字节 */

/* 全局变量-------------------------------------------------------------------*/

/* 私有函数原型---------------------------------------------------------------*/
void usart1_tx_en(uint8_t enState);


/**
  * @brief  定时器1中断函数
  */
void TIM1_UP_IRQHandler(void)
{
    if(TIM_GetITStatus(TIM1, TIM_IT_Update) != RESET) 
    {
        /* 组件计时节拍接口 */
        module_tick_inc(1);
        
        TIM_ClearITPendingBit(TIM1, TIM_FLAG_Update);
    }
}

/**
  * @brief  串口1中断
  */
void USART1_IRQHandler(void)
{
    /* 串口1空闲中断 */
    if(USART_GetITStatus(USART1,USART_IT_IDLE) != RESET)
    {
        USART1->SR;
        USART1->DR;
        
        /* 这里写接收处理 */
        ymodem_write_rx_buf(&ymodem, usart1DmaRxBuf, sizeof(usart1DmaRxBuf) - DMA_GetCurrDataCounter(DMA1_Channel5));
        /* dma重配置 */
        usart1_dma_rx_reconfig(sizeof(usart1DmaRxBuf));
    }
}

/**
  * @brief  串口1接收的dma中断
  */
void DMA1_Channel5_IRQHandler(void)
{
    /* DMA传输完成中断 */
    if(DMA_GetITStatus(DMA1_IT_TC5) != RESET)
    {
        /* 这里写接收处理 */
        ymodem_write_rx_buf(&ymodem, usart1DmaRxBuf, sizeof(usart1DmaRxBuf));
        /* dma重配置 */
        usart1_dma_rx_reconfig(sizeof(usart1DmaRxBuf));
        
        DMA_ClearITPendingBit(DMA1_IT_TC5);
    }
}

/**
  * @brief  串口1发送的dma中断
  */
void DMA1_Channel4_IRQHandler(void)
{
    static uint16_t num;
    
    /* DMA传输完成中断 */
    if(DMA_GetITStatus(DMA1_IT_TC4) != RESET)
    {
        /* 这里写读取发送内容的处理 */
        num = ymodem_read_tx_buf(&ymodem, usart1DmaTxBuf, sizeof(usart1DmaTxBuf)); /* 读出数据 */
        usart1_dma_tx_reconfig(num); /* dma重配置 */
        
        DMA_ClearITPendingBit(DMA1_IT_TC4);
    }
}

/**
  * @brief  串口发送前准备函数
  * 
  * @param  enState : 0失能 1使能
  *
  * @retval None
  */
void usart1_tx_en(uint8_t enState)
{
    if(enState)
    {
        /* 判断当前是否正在发送 发送完成标志置位则不是正在发送 */
        if(USART_GetFlagStatus(USART1, USART_FLAG_TC) != RESET)
        {
            uint16_t num;
            num = ymodem_read_tx_buf(&ymodem, usart1DmaTxBuf, sizeof(usart1DmaTxBuf)); /* 读出数据 */
            if(0 < num)
            {
                usart1_dma_tx_reconfig(num); /* dma重配置 */
            }
            else
            {
                DMA_Cmd(DMA1_Channel4, DISABLE); /* 关闭dma */
            }
        }
    }
    else
    {
        DMA_Cmd(DMA1_Channel4, DISABLE);
    }
}

/**
  * @brief  获取ymodem数据包回调函数
  * 
  * @param  packetNum : 数据包序号 首次从1开始 超出255回到0
  *
  * @param  data      : 有效数据缓冲区(需读出数据)
  *
  * @param  len       : 有效数据长度(包含填充内容0x1A)
  *
  * @retval None
  */
void ymodem_get_packet_callback(uint8_t packetNum, uint8_t *data, uint16_t *len)
{
    uint16_t lenTmp = *len;

    /* 文件信息 */
    if(ymodem_get_file_flag(&ymodem))
    {
        ymodem_get_file_info(&ymodem, &fileInfo); /* 获取文件信息保存至fileInfo结构体 */
        PRINT_LOG("ymodem rec file name:%s, size:%d Byte\r\n", fileInfo.fileName, fileInfo.fileSize);
    } /* 数据 */
    else
    {
        PRINT_LOG("ymodem packet num:%d, len:%d, data: ", packetNum, lenTmp);
        while(lenTmp--)
        {
            PRINT_LOG("%02X ", *data++);
        }
        PRINT_LOG("\r\n");
    }
}

/**
  * @brief  设置ymodem数据包回调函数
  * 
  * @param  packetNum : 数据包序号 首次从1开始 超出255回到0
  *
  * @param  data      : 有效数据存放区(需填充数据)
  *
  * @param  len       : 有效数据长度(不包含填充内容0x1A,组件自动填充)
  *
  * @retval None
  */
void ymodem_set_packet_callback(uint8_t packetNum, uint8_t *data, uint16_t *len)
{
    /* 文件信息 */
    if(ymodem_get_file_flag(&ymodem))
    {
        /* 只发送一个文件 */
        if(fileCnt < 1)
        {
            fileCnt++; /* 文件计数自增 */
            strcpy(fileInfo.fileName, "test_ymodem.txt\0"); /* 文件名 */
            fileInfo.fileSize = 2048; /* 文件长度 */
        } /* 文件计数超出要发送的数量则设置文件长度为0 */
        else
        {
            fileInfo.fileSize = 0;
        }
        ymodem_set_file_info(&ymodem, &fileInfo); /* 设置文件信息从fileInfo结构体 */
    } /* 数据 */
    else
    {
        /* 已发送字节小于文件长度时则设置发送内容 */
        if(sendCnt < fileInfo.fileSize)
        {
            /* 待发送内容超出1024则按照1024长度发送 */
            if((fileInfo.fileSize - sendCnt) >= 1024)
            {
                *len = 1024; /* 设置发送长度 */
                sendCnt += 1024; /* 计数已发送字节 */
            } /* 否则发送剩余长度 */
            else
            {
                *len = fileInfo.fileSize - sendCnt;
                sendCnt = fileInfo.fileSize;
            }
            
            memset((void *)data, packetNum + '0', *len);
        } /* 否则说明发送完毕则设置发送长度为0 */
        else
        {
            *len = 0;
        }
    }
}

/**
  * @brief  main
  */
int main(int argc, char *argv[])
{
    VERSION_LOG("example-ymodem", 1, 0, 0);
    
    /* 串口及其dma初始化 */
    usart1_dma_init_config(115200, usart1DmaTxBuf, sizeof(usart1DmaTxBuf), usart1DmaRxBuf, sizeof(usart1DmaRxBuf));
    /* 定时器初始化 1ms */
    tim1_init_config(100-1, 720-1);

    /* ymodem组件初始化 */
    ymodem_init(&ymodem, ymodemBuf, sizeof(ymodemBuf), usart1_tx_en, ymodem_get_packet_callback, ymodem_set_packet_callback, 1000, 2);
#if YMODEM_TX_RX_TEST
    /* 启动ymodem接收 */
    ymodem_rx_start(&ymodem, YMODEM_RX_FLAG_CRC);
#endif
    
    while(1)
    {
        static uint8_t ret;
#if YMODEM_TX_RX_TEST
        ret = ymodem_rx_poll(&ymodem); /* ymodem接收轮询处理 */
        if(RET_OK == ret)
        {
            DEBUG_LOG("ymodem rx success");
        }
        else if(RET_ERR == ret)
        {
            DEBUG_LOG("ymodem rx failed");
        }
        else if(RET_TIMEOUT == ret)
        {
            DEBUG_LOG("ymodem rx timeout");
        }
#else
        ret = ymodem_tx_poll(&ymodem); /* ymodem发送轮询处理 */
        if(RET_OK == ret)
        {
            fileCnt = 0;
            sendCnt = 0;
            DEBUG_LOG("ymodem tx success");
        }
        else if(RET_ERR == ret)
        {
            fileCnt = 0;
            sendCnt = 0;
            DEBUG_LOG("ymodem tx failed");
        }
        else if(RET_TIMEOUT == ret)
        {
            fileCnt = 0;
            sendCnt = 0;
            DEBUG_LOG("ymodem tx timeout");
        }
#endif
    }
}

